package com.hw.common.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.*;

/*****
 * <pre>
 * 类名称：Base64
 * 类描述：Base64编码实现类
 * 创建人：JokenWang
 * 创建时间：2015年1月9日 下午2:04:05
 * </pre>
 *
 * @version 1.0.0
 */
@SuppressWarnings("restriction")
public class Base64 {
   private static final Logger LOGGER = LoggerFactory.getLogger(Base64.class);
   /**
    * 码表
    */
   public static char[] encodeTable = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
         'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
         'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
   
   /**
    * Base64的编码;
    *
    * @param value
    * @return
    */
   public static String encode(byte[] value) {
      StringBuilder sb = new StringBuilder();
      // 获取编码字节是3的倍数;
      int len = value.length;
      int len3 = len / 3;
      // 先处理没有加换行符;
      for (int i = 0; i < len3; i++) {
         
         // 得到第一个字符;
         int b1 = (value[i * 3] >> 2) & 0x3F;
         char c1 = encodeTable[b1];
         sb.append(c1);
         
         // 得到第二个字符;
         int b2 = ((value[i * 3] << 4 & 0x3F) + (value[i * 3 + 1] >> 4)) & 0x3F;
         char c2 = encodeTable[b2];
         sb.append(c2);
         
         // 得到第三个字符;
         int b3 = ((value[i * 3 + 1] << 2 & 0x3C) + (value[i * 3 + 2] >> 6)) & 0x3F;
         char c3 = encodeTable[b3];
         sb.append(c3);
         
         // 得到第四个字符;
         int b4 = value[i * 3 + 2] & 0x3F;
         char c4 = encodeTable[b4];
         sb.append(c4);
         
      }
      
      // 如果有剩余的字符就补0;
      // 剩余的个数;
      int less = len % 3;
      if (less == 1) {// 剩余一个字符--补充两个等号;;
         
         // 得到第一个字符;
         int b1 = value[len3 * 3] >> 2 & 0x3F;
         char c1 = encodeTable[b1];
         sb.append(c1);
         
         // 得到第二个字符;
         int b2 = (value[len3 * 3] << 4 & 0x30) & 0x3F;
         char c2 = encodeTable[b2];
         sb.append(c2);
         sb.append("==");
         
      } else if (less == 2) {// 剩余两个字符--补充一个等号;
         
         // 得到第一个字符;
         int b1 = value[len3 * 3] >> 2 & 0x3F;
         char c1 = encodeTable[b1];
         sb.append(c1);
         
         // 得到第二个字符;
         int b2 = ((value[len3 * 3] << 4 & 0x30) + (value[len3 * 3 + 1] >> 4)) & 0x3F;
         char c2 = encodeTable[b2];
         sb.append(c2);
         
         // 得到第三个字符;
         int b3 = (value[len3 * 3 + 1] << 2 & 0x3C) & 0x3F;
         char c3 = encodeTable[b3];
         sb.append(c3);
         sb.append("=");
         
      }
      
      return sb.toString();
   }
   
   /**
    * Base64的解码;
    *
    * @param value
    * @return
    */
   public static String decode(byte[] value) {
      // 每四个一组进行解码;
      int len = value.length;
      int len4 = len / 4;
      StringBuilder sb = new StringBuilder();
      // 除去末尾的四个可能特殊的字符;
      int i = 0;
      for (i = 0; i < len4 - 1; i++) {
         // 第一个字符;
         byte b1 = (byte) ((char2Index((char) value[i * 4]) << 2) + (char2Index((char) value[i * 4 + 1]) >> 4));
         sb.append((char) b1);
         // 第二个字符;
         byte b2 = (byte) ((char2Index((char) value[i * 4 + 1]) << 4) + (char2Index((char) value[i * 4 + 2]) >> 2));
         sb.append((char) b2);
         // 第三个字符;
         byte b3 = (byte) ((char2Index((char) value[i * 4 + 2]) << 6) + (char2Index((char) value[i * 4 + 3])));
         sb.append((char) b3);
      }
      
      // 处理最后的四个字符串;
      for (int j = 0; j < 3; j++) {
         int index = i * 4 + j;
         if ((char) value[index + 1] != '=') {
            if (j == 0) {
               byte b = (byte) ((char2Index((char) value[index]) << 2) + (char2Index((char) value[index + 1]) >> 4));
               sb.append((char) b);
            } else if (j == 1) {
               byte b = (byte) ((char2Index((char) value[index]) << 4) + (char2Index((char) value[index + 1]) >> 2));
               sb.append((char) b);
            } else if (j == 2) {
               byte b = (byte) ((char2Index((char) value[index]) << 6) + (char2Index((char) value[index + 1])));
               sb.append((char) b);
            }
         } else {
            break;
         }
      }
      
      return sb.toString();
   }
   
   /**
    * 将码表中的字符映射到索引值;
    *
    * @param ch
    * @return
    */
   public static int char2Index(char ch) {
      if (ch >= 'A' && ch <= 'Z') {
         return ch - 'A';
      } else if (ch >= 'a' && ch <= 'z') {
         return 26 + ch - 'a';
      } else if (ch >= '0' && ch <= '9') {
         return 52 + ch - '0';
      } else if (ch == '+') {
         return 62;
      } else if (ch == '/') {
         return 63;
      }
      return 0;
   }
   
   /***
    * <pre>
    * 功能：根据传入的文件路径，进行文件BASE64编码
    * 创建人：JokenWang
    * 创建时间：2015年1月9日 下午3:11:28
    * </pre>
    *
    * @param filePath
    *            文件路径
    * @return
    * @version 1.0.0
    */
   public static String GetDataStr(String filePath) {
      // 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
      byte[] data = null;
      
      // 读取图片字节数组
      try {
         InputStream in = new FileInputStream(filePath);
         data = new byte[in.available()];
         in.read(data);
         in.close();
      } catch (IOException e) {
         LOGGER.error("{}", e);
      }
      
      // 对字节数组Base64编码
      BASE64Encoder encoder = new BASE64Encoder();
      return encoder.encode(data);// 返回Base64编码过的字节数组字符串
   }
   
   /**
    * <pre>
    * 功能：文件BASE64编码后字节流
    * 创建人：JokenWang
    * 创建时间：2015年1月9日 下午3:18:02
    * </pre>
    *
    * @param imgbytes 文件字节流
    * @return
    * @version 1.0.0
    */
   public static String GetDataStr(byte[] databytes) {
      // 对字节数组Base64编码
      BASE64Encoder encoder = new BASE64Encoder();
      return encoder.encode(databytes);// 返回Base64编码过的字节数组字符串
   }
   
   /**
    * <pre>
    * 功能：获取文件base64编码后的字符串
    * 创建人：JokenWang
    * 创建时间：2015年1月9日 下午2:56:02
    * </pre>
    *
    * @param dataStr 文件base64编码后的字符串
    * @return
    * @version 1.0.0
    */
   public static byte[] getDataBytes(String dataStr) {
      try {
         if (dataStr == null) {
            return null;
         }
         BASE64Decoder decoder = new BASE64Decoder();
         byte[] bytes = decoder.decodeBuffer(dataStr);
         return bytes;
      } catch (Exception e) {
         LOGGER.error("{}", e);
      }
      return null;
   }
   
   /***
    * <pre>
    * 功能：生成文件
    * 创建人：JokenWang
    * 创建时间：2015年1月9日 下午3:12:43
    * </pre>
    *
    * @param
    * @return
    * @version 1.0.0
    */
   public static boolean GenerateFile(String dataStr, String filePath) {// 对字节数组字符串进行Base64解码并生成图片
      if (dataStr == null) // 文件数据为空
      {
         return false;
      }
      BASE64Decoder decoder = new BASE64Decoder();
      try {
         // Base64解码
         byte[] bytes = decoder.decodeBuffer(dataStr);
         for (int i = 0; i < bytes.length; ++i) {
            if (bytes[i] < 0) {// 调整异常数据
               bytes[i] += 256;
            }
         }
         // 生成文件
         OutputStream out = new FileOutputStream(filePath);
         out.write(bytes);
         out.flush();
         out.close();
         return true;
      } catch (Exception e) {
         LOGGER.error("{}", e);
         return false;
      }
   }
}